home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Gold Collection
/
Software Vault - The Gold Collection (American Databankers) (1993).ISO
/
cdr24
/
sdf21.zip
/
SDF.ASM
< prev
next >
Wrap
Assembly Source File
|
1993-05-20
|
25KB
|
1,023 lines
Title 'SDF : Speedy Disk Formatter'
; **************************************************************************
; * THIS PROGRAM IS PUBLIC DOMAIN. You Are Free To Use It And Redistribute *
; * It, As Long As No Profit Is Made Out Of It. Redistribution Costs May *
; * Not Exceed $5. This Notice May Not Be Removed Or Altered In Any Way. *
; * Use At Your Own Risk. Author Will Not Be Held Responsible For Any Dama-*
; * ge That Might Result Of Use Or Misuse. Enjoy. *
; **************************************************************************
; This program is inspired from QDR by Vernon D. Buerg, which unfortunately
; has a bug in handling 3.5" floppies.
; Better late than never, I dedicate this program to Ward Christensen, who
; showed us the way in the good old CP/M days ...
; Jacques Pierson, Belgrade (Belgium), November 1987.
; CIS 76446,1516
; Modification history:
; September 1990: fixed bug with DMA boundary errors, and added code to turn
; off the drive motor quickly.
; October 1990: fixed bug in above bug fix.
M24 = 0 ;set to one at work, for an Olivetti M24 (ATT 6300)
bell equ 7
bs equ 8
lf equ 0Ah
cr equ 0Dh
escape equ 1Bh
ulc equ 0C9h ;graphic char - Upper Left Corner
llc equ 0C8h ;Lower Left Corner
urc equ 0BBh ;Upper Right Corner
lrc equ 0BCh ;Lower Right Corner
vb equ 0BAh ;Vertical Border
hb equ 0CDh ;Horizontal Border
;
hsr equ 0EFh ;Head Step Rate : 4 ms
hst equ 0 ;Head Settle Time : 0 ms
;
SDF segment
assume ds:SDF, ss:SDF ,cs:SDF ,es:SDF
org 0100h ;make this a COM file
start: jmp GetCmdLine
; First describe our Disk Base Parms. We will make INT 1Eh to point here
; while formatting. Put at head of program so people without an assembler
; can easily patch this area w/ DEBUG.
OurDBP equ $
db hsr ;high nibble : heads step rate
;low nibble, head unload time
db 2 ;DMA mode
db 255 ;clock ticks before stopping drive motor
db 2 ;sector size - 2 => 512 bytes
db 9 ;How many sectors per track
db 42 ;Gap length between sectors for R/W ops
db -1 ;data length - Not used
db 80 ;Gap length when formatting
db 0F6h ;Formatting char. Dos likes F6's
db hst ;Head settle time in ms.
db 1 ;Motor speed up time in 1/4 sec.
Welcome db cr,lf,'Speedy Disk Formatter, V1.0, '
db '(c) Jacques Pierson, Nov 1987$'
UsageMessage equ $
db cr,lf,lf,'Usage: SDF drv: [switches]',cr,lf
db 'drv: mandatory and is either A: or B:,',cr,lf
db 'No switch => format standard 360K diskette, no verify',cr,lf
db '/Q => format Quad density (3',0abh,'" 720K disk)',cr,lf
db '/V => force Verify after format',cr,lf
db 'Multiple switches may be combined, e.g. SDF b:/q/v.'
db cr,lf,lf,'$'
DriveMissing db cr,lf,lf,'Invalid or missing Drive Spec !$'
WrongSwitch db cr,lf,lf,'Unknown /switch in command line !$'
InsertDisk db cr,lf,lf,'Insert diskette in drive '
Drive db 'A, and press ENTER when ready ...$'
Again db cr,lf,lf,'Format complete,'
Clusters db ' K available to user.'
db cr,lf,'Press ENTER to format another diskette, '
db 'or ESCape to quit...$'
Formatting db cr,lf,lf,'Formatting '
DiskType db 'DSDD, Without$'
Verify db ' Verify.',cr,lf,'$'
Track db cr,'Track: '
TrackNr db ' Side: '
SideNr db ' $'
ShowRetry db bs,'R$'
WritingBoot db ' - writing BOOT$'
WritingFAT db ', FATs$'
WritingDIR db ', DIR.$'
ErrorTbl db 1,'Invalid command '
db 2,'Address mark not found. '
db 4,'Requested sector not found. '
db 8,'DMA overrun on operation. '
db 10h,'Bad CRC on diskette read/write.'
db 20h,'Controller failure. '
db 40h,'SEEK operation failed. '
EndOfErrTbl equ $
FatalErr db bell,cr,lf,lf,'Door Open, Write-protected disk,'
db ' or Drive Fails to respond.'
db cr,lf,'Please fix problem and hit Enter to continue,'
db 'or ESCape to abort...$'
BadClusters db cr,lf,lf,'Bad sectors :'
BadClNr db ' Cluster(s) disabled.',cr,lf,lf,'$'
;
ErrBadSec db bs,bs,', Sec: '
ErrSec db ' , Error '
ErrCode db ' hex : '
ErrMsg db 'Unknown error. ',cr,lf,'$'
;
;
; Flags, set according to switches
;
OptionsFlag db 0 ;default is No Verify, Normal Disk
CtrlBreak db 0 ;Ctrl-Break flag on entry
;
; Disk characteristics, other parms are found in BootSector
;
DirSecs dw 7 ;DIRectory size in sectors
DskTrks db 40 ;Cyls/disk
CurTrk db -1 ;Current track
CurDrv db 0 ;Current drive, binary, BIOS way (A:=0,..)
NeedSetup db 1 ;nonzero if default parms are in effect
even ;Align for those w/8086 processors
RetryCount dw 0 ;Count of retries
MaxTries dw 2 ;Maximum retries attempted
BadSecCnt dw 0 ;Count of Bad Sectors
NextSec dw 0 ;Temp storage for next sector #
INT1Eoff dw 0 ;INT 1Eh offset
INT1Eseg dw 0 ;INT 1Eh segment
INT24off dw 0 ;Critical error handler offset
INT24seg dw 0 ;Critical error segment
;
HexTbl db '0123456789abcdef'
;
ID_tbl dw Side0 ;addr of table of ID's for track 0, side 0
Side0 db 0,0,1,2
db 0,0,2,2
db 0,0,3,2
db 0,0,4,2
db 0,0,5,2
db 0,0,6,2
db 0,0,7,2
db 0,0,8,2
db 0,0,9,2 ;end of side 0
db 0,1,1,2 ;side 1 now
db 0,1,2,2
db 0,1,3,2
db 0,1,4,2
db 0,1,5,2
db 0,1,6,2
db 0,1,7,2
db 0,1,8,2
db 0,1,9,2 ;end of track, side 1
SideLen equ 36
;
;
; Anatomy of our Boot sector
;
BootSector equ $
jmp BootMsg
db 'SDF v01' ;OEM name, 8 chars
dw 512 ;Sector size
db 2 ;Cluster size in sectors
dw 1 ;Reserved sectors
db 2 ;Number of FATs
DirSize dw 112 ;Directory entries
TotSecs dw 720 ;Total sectors
MediaDes db 0FDh ;Media descriptor
FatSize dw 2 ;FAT size in sectors
dw 9 ;Sectors per Track
dw 2 ;Number of heads
dw 0 ;Number of hidden sectors
db 0 ;filler
db 0 ;head
db 10 ;length of BIOS file
db hsr ;The DPB, remember ?
db 2
db 25h
db 2
db 9
db 42
db -1
db 80
db 0F6h
db hst
db 1
NoBootMsg equ $
db cr,lf,lf
db ulc,50 DUP (hb),urc,cr,lf
db vb,' This diskette has been formatted by SDF and ',vb,cr,lf
db vb,' contains no system to boot from. Either ',vb,cr,lf
db vb,' remove it and hit a key to boot from hard disk ',vb,cr,lf
db vb,' if any, or replace it with another disk with a ',vb,cr,lf
db vb,' system to boot from and hit a key when ready. ',vb,cr,lf
db llc,50 DUP (hb),lrc,cr,lf,lf,0
BootMsg:
cli ;no interrupts
cld ;forward direction
mov AX,07C0h ;Boot runtime address
mov DS,AX ;to DS
mov ES,AX
mov SS,AX
mov SP,0 ;temp stack at top of segment
mov SI,(OFFSET NoBootMsg - OFFSET BootSector) ;Msg ptr
BNextChar:
lodsb ;Get byte fm msg
or AL,AL ;a null ?
je ReBoot ;yes, print msg done
mov AH,0Eh ;print char, no bells and whistles
int 10h ;Bios output char INT
jmp SHORT BNextchar ;loop for all string
;
ReBoot: xor AH,AH ;wait for key hit
int 16h
int 19h ;and try booting again
BEndOfStuff equ $
db (510 - (BEndOfStuff - BootSector)) DUP (0) ;filler
db 55h,0AAh ;DOS disk signature
;
; End of boot sector
;
;
; First sector of File Allocation Table
;
FatSec1 equ $
db 0FDh ;FAT - Media descriptor
db 0FFh
db 0FFh
db 509 DUP (0) ;to get a full sector
FatSec2 db 512 DUP (0) ;FAT, second sector
db 512 DUP (0) ;FAT, third sector
;
DirSec1 equ $
DskLbl db 'SDF--------' ;Dir entry for disk label, 11 char
db 28h ;Attributes : Label + Archive
db 10 DUP (0)
TimeLo db 0
TimeHi db 0
Date dw 0
db 486 DUP (0) ;full sector
;
DirSec2 db 512 DUP (0) ;2nd and other sectors
;
;
; Control-Break handler : DO NOT give user a chance to exit w/^C or Break
; without resetting the environement...
;
ControlBreak:
iret ;trap ^C and simply return
;
;
; Critical Error handler: Same as above. Note that, contrary to documentation
; (under DOS 2.1 at least), selecting 'a' under Abort/Retry/Fail does not put
; you into INT 23.
;
CritError:
push AX
push DX
push DS
push CS
pop DS
call Restore
pop DS
pop DX
pop AX
jmp far cs:[INT24off] ;go to the previous handler
;
; Let's go to it now
;
GetCmdLine:
mov DX,offset Welcome ;print welcome msg
call PrintString
mov SI,80H ;Peek at input bfr char count
lodsb ;get byte
cbw ;make word
or AX,AX ;any option ?
jne GCL1 ;yes
Usage: mov DX,offset UsageMessage
call PrintString ;Print and fall thru ErrorExit
;
; Error Exit, w/ return code 1, Normal Exit, w/ return code 0
;
ErrorExit:
mov AL,1
jmp SHORT DoExit
;
Abort: call Restore ;Restore INT 1E, INT 35
;
Exit: mov AL,0 ;normal exit, no error
DoExit: mov AH,4Ch ;Program Exit
int 21h
;
;
; Carry on parsing command line
;
GCL1: mov CX,AX ;got something in cmd line, count to CX
call ParseSwitches ;Parse cmd line "/" switches
mov SI,81h ;Get drive spec
GCL2: lodsb
cmp AL,' ' ;skip spaces
loopz GCL2
jcxz Usage ;Nuts, give Usage Msg
cmp AL,cr
jz Usage
and AL,5fh ;Make drive letter uppercase
mov Drive,AL ;Put drive letter in msg
sub AL,'A' ;make binary, BIOS way
mov CurDrv,AL ;Store in current drive
cmp AL,1 ;Drive MUST be 0 or 1
jg BadDrive
lodsb
cmp AL,':' ;Make sure this WAS a drive spec
jne BadDrive ;no, it was not
jmp Setup ;Yes, indeed
BadDrive:
mov DX,OFFSET DriveMissing
call PrintString
jmp Usage
;
;
A$Ret: ret
;
; Parse command line switches
;
ParseSwitches:
mov DI,81h ;peek at cmd line
PS1: mov AL,'/'
repne scasb ;search for "/", length in CX
jne A$Ret
jcxz A$Ret ;none, or no more
mov BYTE PTR [DI-1],cr ;Got a "/", put a CR for later use
cmp BYTE PTR [DI-2],' ' ;Previous char was space ?
jne PS2 ;no
mov BYTE PTR [DI-2],cr ;yes, force to CR
PS2: mov SI,DI
lodsb ;get switch
and AL,5Fh ;Force uppercase
PS3: cmp AL,'V' ;/Verify ?
jne PS4 ;no
mov OptionsFlag,1 ;yes, remember that
mov WORD PTR DskLbl+6,'V+' ;put in disk label
mov BYTE PTR DiskType+10,'$' ;truncate "Without" msg
jmp PS1 ;parse next
PS4: cmp AL,'Q' ;/Quad density ?
jne PS5 ;no, unknown switch
mov BYTE PTR DiskType+2,'Q' ;Flag, and Description
mov DskTrks,80 ;80 tracks
mov FatSize,3 ;FAT is 3 sectors long
mov TotSecs,1440 ;1440 sectors
mov MediaDes,0F9h ;to Boot Sector
mov WORD PTR DskLbl+8,'Q+' ;put in disk label
jmp PS1 ;parse next switch
PS5: mov DX,OFFSET WrongSwitch
call PrintString
jmp Usage
;
; Restore : Restore the world as it was on entry
;
Restore:cmp NeedSetup,0 ;see if we need to do this
jnz Res1 ;if not
mov NeedSetup,1
lds DX,DWORD PTR INT1Eoff ;previous INT 1Eh vector
mov AX,251Eh ;restore it
int 21h
push CS ;restore DS
pop DS
mov AH,0 ;Reset Disk System
int 13h
mov AX,3301h ;set Ctrl-Break flag
mov DL,CtrlBreak ;restore as was on entry
int 21h
Res1: ret
;
;
; Setup : Set up the world
;
Setup: mov AH,AL ;colon to AH
mov AL,CurDrv
add AL,'A'
mov WORD PTR DskLbl+4,AX ;put DriveSpec in disk label
mov AX,3300h ;Get CtrlBreak flag
int 21h
mov CtrlBreak,DL ;save flag
mov DX,OFFSET ControlBreak ;our handler
mov AX,2523h ;Set Interrupt Vector 23h
int 21h
mov AX,3524h ;get Interrupt Vector 24h
int 21h
mov INT24off,BX
mov INT24seg,ES
mov DX,OFFSET CritError ;our handler
mov AX,2524h ;Set Interrupt Vector 24h
int 21h
mov AX,351Eh ;get Interrupt Vector 1Eh
int 21h
mov INT1Eoff,BX
mov INT1Eseg,ES
push CS
pop ES
;fall thru format loop
;
Do_It: mov DX,OFFSET InsertDisk ;say "Insert diskette in drive.."
call PrintString
;
GetChar:mov AH,0 ;get char function
int 16h
cmp AL,escape
jne GC1
jmp Abort
GC1: cmp AL,cr
jne GetChar ;Escape or CR only !
cmp NeedSetup,0 ;see if we need to do this
je GC2 ;if not
mov NeedSetup,0
mov DX,OFFSET OurDBP ;our DBP
mov AX,251Eh ;Set Interrupt Vector 1Eh
int 21h
mov AH,0 ;Reset Disk System
int 13h ;our DBP is now in effect
mov AX,3301h ;set flag
xor DL,DL ;set checking OFF
int 21h
GC2: mov DX,OFFSET Formatting ;"Formatting..."
call PrintString
mov DX,OFFSET Verify
call PrintString
mov BadSecCnt,0 ;no bad sector so far
call PrepareFat
;
; Format all disk now
;
call DoFormat ;Here we go
mov AX,BadSecCnt ;any bad sector ?
or AX,AX
je NoBadSec ;no
mov SI,OFFSET BadClNr ;Pointer to decimal places
call AX2dec ;convert to decimal
mov DX,OFFSET BadClusters ;Bad Clusters msg
call PrintString
;
; Write Boot, FAT, DIR
;
NoBadSec:call WriteBFD ;write Boot, Fat, Dir
;
; Show available space
;
mov AH,0Dh ;reset disk system
int 21h
mov AH,36h ;get free space
mov DL,CurDrv ;for our drive
inc DL ;DOS way
int 21h
mov AX,BX ;clusters to AX
mov SI,OFFSET Clusters
call AX2dec ;convert and fall thru print
;
; Done - prompt for another disk to format
;
mov DX,OFFSET Again ;"Hit enter to format another..."
call PrintString
call MotorOff ;Turn motor off
call Whistle ;Wake him up
jmp GetChar ;get char
;
; Prepare first FAT sector - This stuff required for multiple formatting
;
PrepareFat:
sub AX,AX ;clear FAT to all zeros
mov DX,FatSize ;How many sectors ?
mov DI,OFFSET FatSec1
PF1: mov CX,512/2 ;sector size, in words
repz stosw ;for speed
dec DX ;next FAT
jnz PF1
mov AL,MediaDes ;get Media Descriptor from Boot Sec
mov BYTE PTR FatSec1,AL ;move in place
mov WORD PTR FatSec1+1,0FFFFh
ret
;
; Here to REALLY format a disk
;
DoFormat:
mov CurTrk,-1 ;Initialize track nr
NextTrk: ;Prepare table for Track/sect. ID's
inc CurTrk ;Next track
mov CH,CurTrk ;to CH
cmp CH,DskTrks ;All done ?
jb NT1 ;not yet
ret ;yes, return
NT1: mov DI,ID_tbl ;Point to table
mov AL,18 ;18 sectors per Cyl
NT2: mov [DI],CH ;move Track # in table
add DI,4 ;point to next entry
dec AL ;all done ?
jnz NT2 ;No, loop
mov AH,1 ;Give user a chance to abort
int 16h ;Keyboard hit ?
jz NT3 ;no
cmp AL,escape ;yes, Escape to abort ?
jne NT3
jmp Abort
;
NT3: mov AX,0509h ;Format Track, 9 sectors/trk
mov BX,ID_tbl ;track id table address, side 0
mov DL,CurDrv ;current drive
mov DH,0 ;Side 0
mov CL,1 ;First sec is #1
call PrintProgress ;Print progress (Track#, Side #)
int 13h ;Format track, side 0
jnc NT3V ;No Carry, no error
call Retry ;Carry set, Shall we retry ?
jnc NT3 ;yes, if we come here w/Carry clear
;else, give up
NT3V: test OptionsFlag,1 ;Should we verify ?
jz NT4 ;No, next side
;
NT3R: mov AX,0409h ;Verify, 9 sectors per track
int 13h
jnc NT4 ;No carry, no error
call Retry ;Carry set, retry ?
jnc NT3R ;Yes, if Carry clear, else give up
NT4: mov DH,1 ;Side 1
mov AX,0509h ;Format Track, 9 sectors/trk
mov BX,ID_tbl ;track id table address, side 1
add BX,SideLen
mov DL,CurDrv ;current drive
mov CL,1 ;First sec is #1
call PrintProgress ;Print progress (Track#, Side #)
int 13h ;Format track, side 1
jnc NT4V ;no error
call Retry ;Carry set, error
jnc NT4 ;Retry if Carry clear, else give up
NT4V: test OptionsFlag,1 ;Should we verify ?
jz NextTrk ;no, next track
;
NT4R: mov AX,0409h ;Verify, 9 sectors per track
int 13h
jc NT5 ;error !
jmp NextTrk ;no error, next track
NT5: call Retry ;Carry set, retry ?
jnc NT4R ;yes
jmp NextTrk ;no, next track
;
Retry: cmp AH,3 ;Door open/Write protected ?
je R1 ;yes
cmp AH,80h ;Attachment failed to respond ?
jne R2 ;no, other error
R1: mov DX,OFFSET FatalErr ;tell him he'd better close the door
call PrintString ;..or remove the write-protect tab
pop AX ;clean up stack, we won't return
pop AX ;two calls to clean up
jmp GetChar ;OK, we may restart now
R2: cmp AH,9 ;DMA boundary error?
jne R4 ;no, other error
push CX ;save registers
push SI
mov DI,ES ;compute offset of next DMA page
neg DI
mov CL,4
shl DI,CL
cmp DI,EndCode
ja R3 ;if it's not in the code segment
mov DI,EndCode ;don't clobber code
R3: mov SI,ID_tbl ;move the table pointer
mov ID_tbl,DI
mov CX,SideLen ;move the table itself
rep movsw
cmp SI,DI
pop SI ;restore registers
pop CX
je R4 ;if this should already be fixed
clc
ret
R4: push DX
mov DX,OFFSET ShowRetry ;Show 'R' to indicate a retry
call PrintString
pop DX
inc RetryCount
mov DI,MaxTries ;limit exceeded ?
cmp RetryCount,DI
ja SecIsBad ;Yes, this one is really bad
mov AH,0 ;No, Reset Disk System
int 13h
clc ;clear carry
ret ;and return to try again
;
; If we come here, we really have to deal with a bad sector
;
SecIsBad: call ShowBadSec
inc BadSecCnt ;count it
call MarkBad ;Mark whole cluster
mov RetryCount,0 ;Reset retry count
stc ;Set Carry to indicate "give up"
ret ;go process next side or track
;
;
; Mark a bad sector (cluster) in FAT
;
MarkBad:push AX
push BX
push CX
push DX
push DI
push SI
push DS ;We have to fetch..
mov AX,40h ;.. the faulty sector
mov DS,AX ;.. in the BIOS area
mov BX,47h
mov CL,BYTE PTR [BX] ;Get sector number
pop DS
mov AL,CH ;Track # to AL; AH is already 0
xor CH,CH
cmp DH,0 ;Side 0 ?
je MB1
add CL,9 ;Side 1, add 9 sects for side 0
MB1: shl AX,1 ;* 2 heads
mov BX,9 ;* 9 sectors per track
mul BX ;compute absolute sector #
add AX,CX
sub AX,FatSize ;minus 1st FAT size
sub AX,FatSize ;minus 2nd FAT size
sub AX,DirSecs ;minus Directory size
mov BL,2 ;disk heads
div BX
add AX,1
mov CX,3
mul CX
shr AX,1 ; / 2
mov DI,AX
lea SI,[DI+FatSec1] ;pointer into FAT
mov DI,SI
lodsw ;get cluster entry
mov DX,0FF70h ;12 bits, left aligned
jb MB2 ;if even
mov DX,0FF7h ;if odd
MB2: or AX,DX ;merge w/ word to mark bad
stosw ;store back in FAT
pop SI
pop DI
pop DX
pop CX
pop BX
pop AX
ret
;
; Write Boot sector, then FATs, then DIR.
;
WriteBFD:
mov DX,OFFSET WritingBoot
call PrintString
mov AL,CurDrv
lea BX,BootSector ;boot sector
mov CX,1 ;1 sector to write
mov DX,0 ;absolute sector 0
call AbsSecWrite
;
; Write FAT(s)
;
push DX ;Preserve Sector Nr
mov DX,OFFSET WritingFAT ;"FATs"
call PrintString
pop DX
mov AL,CurDrv ;current drive
lea BX,FatSec1 ;point to FAT 1st sector
mov CX,1 ;1 sector write
inc DX ;DX knows which
call AbsSecWrite
mov CX,FatSize ;sectors/FAT
dec CX ;One written already
lea BX,FatSec2 ;get FAT 2nd sector
mov AL,CurDrv ;current drive
inc DX ;next sector(s)
call AbsSecWrite
add DX,CX ;count sectors written this time
;
; Write second FAT
;
mov AL,CurDrv ;current drive
mov BX,OFFSET FatSec1 ;FAT
mov CX,1 ;1 sector, DX knows which
call AbsSecWrite
mov CX,FatSize ;How many remaining ?
dec CX ;One already written
mov BX,OFFSET FatSec2 ;point to FAT 2nd sector
mov AL,CurDrv ;current drive
inc DX ;next FAT sector(s)
call AbsSecWrite
add DX,CX
mov NextSec,DX ;remember next sector to write
;
; Write Directory
;
mov DX,OFFSET WritingDIR ;"DIRectory"
call PrintString
;
; Update Disk Label Date and Time
;
mov AH,2Ch ;Get Time
int 21h
mov BX,CX ;Minutes, Seconds
mov AX,CX
mov CL,3
shl CH,CL ;Shift to move hour in place
shr BL,CL ;Shift to keep high 3 bits of min
add CH,BL ;merge
mov TimeHi,CH ;move in place
and AL,7 ;keep min. lower 3 bits
shl AL,1 ;shift
mov CL,5
shr DX,CL ;Shift seconds
add DH,AL ;merge
mov TimeLo,DH ;move in place
mov AH,2Ah ;Get Date
int 21h
sub CX,1980 ;From 1980 on
shl CL,1
mov BX,DX
mov AH,CL
mov CL,3
shr DH,CL
add AH,DH
mov CL,5
shl BH,CL
add BH,DL
mov AL,BH
mov Date,AX ;Move date in place
mov AL,CurDrv ;current drive
mov BX,OFFSET DirSec1 ;First sector of DIR
mov DX,NextSec ;current sector
mov CX,1 ;1 sector to write
call AbsSecWrite
mov AL,CurDrv
mov BX,OFFSET DirSec2
mov CX,DirSecs ;How many sectors
dec CX ;One already written
WD1: push CX
mov CX,1 ;1 sector write
inc DX ;next one
call AbsSecWrite
pop CX ;how many remaining ?
loop WD1
ret ;Done, next disk please.
;
; Print progress : Track nn Side n - inline decimal conversion
;
PrintProgress:
push AX
push DX
mov AL,DH ;Side #
add AL,'0' ;Brute force ascify
mov SideNr,al ;Put side # in msg
mov AL,CH ;get track #
aam ;THE trick
xchg AL,AH ;swap
add AX,'00' ;Ascify
mov WORD PTR TrackNr,AX ;Put track # in msg
mov DX,OFFSET Track ;say "Track..., Side..."
call PrintString
pop DX
pop AX
ret
;
; Here to show that we have a bad sector
;
ShowBadSec:
push AX
push BX
push CX
push DX
push DI
push SI
mov DX,AX ;Save AX for further hex printing
sub BX,BX
mov BL,AH ;remember error code
mov DI,OFFSET ErrorTbl ;Table for INT 13 error codes & msgs
mov AL,AH ;Error code to AL
MOV CX,OFFSET EndOfErrTbl
sub CX,DI ;compute table length
repnz scasb ;search for error code
jnz SBS1 ;Not found, "Unknown Error"
mov SI,DI ;Got it, Ptr to SI
mov CX,31 ;err msg length
mov DI,OFFSET ErrMsg ;Point to destination
repz movsb ;Move Err Msg in place
SBS1: mov AL,DH ;Get AH : error code
call AL2hex ;Convert
mov WORD PTR ErrCode,AX ;move AH (hex) in msg
push DS
mov AX,40h ;Point to BIOS data area
mov DS,AX
mov BX,47h ;the right place in BIOS area
mov AL,BYTE PTR [BX] ;BIOS knows which sector causes problem
pop DS
add AL,'0' ;ascify
mov ErrSec,AL ;move sec # in msg
mov DX,OFFSET ErrBadSec ;give error msg
call PrintString
pop SI
pop DI
pop DX
pop CX
pop BX
pop AX
ret
;
;
; AL2hex : binary AL to 2 hex digits in AX conversion
;
AL2hex: push BX
push CX
push DX
push SI
mov BL,AL ;will use BX as offset to tbl
mov CL,4 ;bits to shift
sub BH,BH
shr BL,CL
and AL,0Fh ;mask off bits
sub AH,AH
mov SI,OFFSET HexTbl ;point to hex tbl
add SI,BX
mov DL,[BX+HexTbl]
mov BX,AX
mov DH,[BX+HexTbl]
mov AX,DX
pop SI
pop DX
pop CX
pop BX
ret
;
;
; AX2dec : routine to convert AX to decimal string at DS:SI
;
AX2dec: push AX
push CX
push SI
xor CL,CL ;clear 10000 counter
s10000: inc CL
sub AX,10000
jnc s10000
add AX,10000 ;one SUB too much
add CL,'0'-1 ;adjust and ascify
mov [SI],CL ;store in string
inc SI
xor CL,CL ;clear 1000 counter
s1000: inc CL
sub AX,1000
jnc s1000
add AX,1000 ;one SUB too much
add CL,'0'-1 ;adjust and ascify
mov [SI],CL ;store in string
inc SI
xor CL,CL ;clear 100 counter
s100: inc CL
sub AX,100
jnc s100
add AX,100 ;one SUB too much
add CL,'0'-1 ;adjust and ascify
mov [SI],CL ;store in string
inc SI
aam ;Convert value <100
xchg AL,AH ;swap
add AX,'00' ;Ascify
mov [SI],AX
pop SI ;restore string ptr
mov CX,5 ; 5 bytes to search
AX2D1: cmp BYTE PTR [SI],'0' ;leading Zero ?
jne AX2D2 ;no or no more
mov BYTE PTR [SI],' ' ;yes, make leading space
inc SI
loop AX2D1 ;loop for all
AX2D2: pop CX
pop AX
ret
;
;
; PrintString : print string pointed by DX, terminated by '$'
;
PrintString:
push ax
mov ah,9
int 21h
pop ax
ret
;
; Absolute sector Write
;
AbsSecWrite:
push AX
push BX
push CX
push DX
int 26h ;absolute sector write
jnb ASW1 ;no carry, no error
xchg CX,DX
mov DH,DL
call ShowBadSec
ASW1: popf
pop DX
pop CX
pop BX
pop AX
ret
;
; MotorOff - Turn drive motor off
;
motor_count equ 440h
;
MotorOff:
push ds
xor ax,ax
mov ds,ax
mov byte [motor_count],1 ;turn off drive motor next timer tick
pop ds
ret
;
; Whistle - Wolf's whistle
;
i8253 equ 40h ;Timer chip base address
i8255 equ 60h ;PPI chip base address
;
Whistle:
push AX
mov AL,0B6h ;Counter 2, 2 bytes count, mode 3
out (i8253+3),AL ;Write Mode Word
mov AX,1000 ;Divisor
push AX
out (i8253+2),AL ;load lo byte
xchg AH,AL
out (i8253+2),AL ;load hi byte
in AL,(i8255+1) ;8255, port B
or AL,3 ;turn on bottom two bits, spkr on
out (i8255+1),AL
pop AX
W1: call SwLoop ;soft timing loop
dec AX
out (i8253+2),AL ;load lo byte
xchg AH,AL
out (i8253+2),AL ;load hi byte
xchg AH,AL
jne W1 ;loop
in AL,(i8255+1) ;8255, port B
and AL,NOT 3 ;turn off bottom two bits, spkr off
out (i8255+1),AL
pop AX
ret
;
; Soft loop for Whistle
;
SwLoop: push CX
mov CX,100
SWL: loop SWL
pop CX
ret
;
; End of code
;
EndCode:
;
SDF ends
;
end start